﻿// Copyright 2008 Chris Varley (http://www.contractdriven.net/)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//Import the ContractDriven Namespace
using ContractDriven;

namespace ContractExample
{

	class ExampleClass : ContractBoundObject
	{
		//some private variables
		private int _myInt;
		private string _myString = string.Empty;

		public ExampleClass()
		{
			//You can either explicity define logic for an Invariant Check
			Invariant(()=> _myInt > -1 && _myInt < 101, "_myInt should be between 0 and 100");
			
			//or use one of the built in checks 
			//(these checks can be used by any contract type, "Require", "Ensure", "Invariant")
			Invariant(()=> Assert.IsInRange(_myInt, 0, 100));
			
			//An invariant follows the same pattern as other contracts, but uses a delegate
			//rather than inline execution (as it can be evaluated at any point.)
            
			Invariant(()=> _myInt != 42, "_myInt must not equal 42");
            Invariant(()=> Assert.IsLengthInRange(_myString, 0, 20));
		}

		public int MyInt
		{
			get
			{
				return _myInt;
			}
			set
			{
                Contract.Require(Assert.NotEqual<int>(42, value));
				//you can assign values as normal...
				_myInt = value;
				//...in this case invariants will be evaluated after the method has returned.	
				//Or, you can assign the value to the property field using the contract.
				//This checks invariants immediatly and is useful in fast fail situations.
				Contract.Assign(this, ref _myInt, value);
			}
		}

		public void SetMyIntAndMyString(int newInt, string newString)
		{
			Require(Assert.IsInRange(newInt, 0, 100));
			Require(Assert.IsNotNullOrEmpty(newString));

			_myInt = newInt;
			_myString = newString;

			Ensure(_myInt == newInt);
			Ensure(_myString == newString);
		}
        
		public void IncrementMyInt()
		{
			//track the object
			var key = Track(_myInt);
		
			_myInt += 1;

			//ensure that the logic performed correctly
			Ensure(_myInt == (int)Before(key) + 1, "_myInt should equal 1 more than original value");
		}

	}
}
